package com.miku.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.miku.blog.domain.UniqueView;
import com.miku.blog.domain.pojo.ResponseResult;
import com.miku.blog.domain.pojo.SystemConstance;
import com.miku.blog.eume.HttpStatusEnum;
import com.miku.blog.exception.SystemException;
import com.miku.blog.service.TouristService;
import com.miku.blog.service.UniqueViewService;
import com.miku.blog.mapper.UniqueViewMapper;
import com.miku.blog.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Miku
 * @description 针对表【tb_unique_view】的数据库操作Service实现
 * @createDate 2022-05-26 17:54:54
 */
@Service
public class UniqueViewServiceImpl extends ServiceImpl<UniqueViewMapper, UniqueView>
        implements UniqueViewService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private TouristService touristService;


    @Override
    public List<UniqueView> getUniqueViewListByGroupByCreateTIme() {
        UniqueViewMapper baseMapper = getBaseMapper();
        List<UniqueView> uniqueViewList
                = baseMapper.getUniqueViewListByGroupByCreateTIme();
        return uniqueViewList;
    }

    @Override
    public List<UniqueView> getUniqueViewListByCreateTime(Date date) {
        if (Objects.isNull(date)) {
            throw new SystemException(HttpStatusEnum.PARAM_ERROR);
        }
        String format = DateUtils.format(date);

        UniqueViewMapper baseMapper = getBaseMapper();
        List<UniqueView> uniqueViewList
                = baseMapper.getUniqueViewListByCreateTime(format);
        return uniqueViewList;
    }



    @Override
    public UniqueView getUniqueViewByCreateTime(Date date){
        LambdaQueryWrapper<UniqueView> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UniqueView::getCreateTime,date);
        return getOne(queryWrapper);
    }


    @Override
    public ResponseResult report() {

        Date dateByZero = DateUtils.getDateByTodayMorning();
        SimpleDateFormat simpleDateFormat = DateUtils.getSimpleDateFormatYMDHMS();
        String format = simpleDateFormat.format(dateByZero);

        String uuid = UUID.randomUUID().toString();
        while (true) {
            //上锁
            if (redisCache.setCacheObjectIfAbsent(SystemConstance.REDIS_UNIQUE_LOCK_KEY,
                    uuid,
                    SystemConstance.REDIS_LOCK_TIME_OUT,
                    SystemConstance.REDIS_TIMEUNIT))
            {
                //检查是否有访问时的对应日期key
                if (redisCache.hasHashKey(SystemConstance.REDIS_UNIQUE_VIEW_KEY, format)) {
                    //若存在 则递增
                    redisCache.incrementByCacheHash(SystemConstance.REDIS_UNIQUE_VIEW_KEY,
                                                    format,
                                                    SystemConstance.VIEW_INCREMENT);
                } else {
                    //若不存在则 设置缓存键  ,初始量为1
                    redisCache.setCacheHashMap(SystemConstance.REDIS_UNIQUE_VIEW_KEY,
                                                format,
                                                SystemConstance.VIEW_INCREMENT);
                    redisCache.setCacheObjectExpireTime(SystemConstance.REDIS_UNIQUE_VIEW_KEY,
                            SystemConstance.REDIS_CACHE_KEY_EXPIRE_TIME,
                            SystemConstance.REDIS_TIMEUNIT);
                }

                //检查锁 是否 与自身的相同  , 若相同 则移除该锁
                String script = "if redis.call('GET',KEYS[1]) == ARGV[1] " +
                                "then return redis.call('DEL',KEYS[1]) " +
                                "else return 0 end";
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                redisScript.setResultType(Long.class);
                redisScript.setScriptText(script);
                redisCache.execute(redisScript, Collections.singletonList(SystemConstance.REDIS_UNIQUE_LOCK_KEY),uuid);
                break;
            } else {
                //若上锁失败,则进入睡眠
                try {
                    Thread.sleep(SystemConstance.REDIS_LOCK_SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        Integer report = touristService.addTourist();

        return ResponseResult.ok().setData(report);
    }
}




